package com.apabi.web.controller.api;

import com.apabi.service.elastic.APICode;
import com.apabi.service.elastic.APIResult;
import com.apabi.service.elastic.Config;
import com.apabi.service.elastic.Elastic;
import com.fasterxml.jackson.databind.JsonNode;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;

/**
 * Created by teng on 2018/1/16.
 */
@SuppressWarnings("unchecked")
@Controller
@RequestMapping("/api/elastic")
public class ElasticController {

    @Autowired
    private Elastic elastic;

    private static final Logger LOGGER = LoggerFactory.getLogger(ElasticController.class);

    @RequestMapping(value = "/{index}",method = RequestMethod.POST,headers ={"Accept=application/json"})
    public @ResponseBody APIResult<Object> postIndex(@PathVariable String index, @RequestBody String source)  {
        APICode apiCode = checkJson(source);
        if(!apiCode.equals(APICode.SUCCESS)){
            return new APIResult<>(apiCode);
        }
        CreateIndexResponse response = null;
        try {
            response = elastic.createIndex(index, source);
        } catch (Exception e) {
            LOGGER.error("create index failed:" + e.getMessage(), e);
            return new APIResult<>(APICode.SYS_EXCEPTION, e.getMessage());
        }
        return new APIResult<>(APICode.SUCCESS, response);
    }

    private APICode checkJson(String source){
        if (StringUtils.isEmpty(source)) {
            return APICode.PARAM_MISSING;
        }
        try {
            Config.JSON_MAPPER.readValue(source, JsonNode.class);
        } catch (Exception e) {
            LOGGER.error("parse json failed:" + source);
            return APICode.PARAM_JSON_ERROR;
        }
        return APICode.SUCCESS;
    }

    @RequestMapping(value = "/{index}/{mapping}",method = RequestMethod.PUT)
    public @ResponseBody APIResult<Object> putMapping(@PathVariable String index,@PathVariable String mapping,@RequestBody String source) {
        APICode apiCode = checkJson(source);
        if(!apiCode.equals(APICode.SUCCESS)){
            return new APIResult<Object>(apiCode);
        }
        PutMappingResponse response = null;
        try {
            response = elastic.putMapping(index, mapping, source);
        } catch (Exception e) {
            LOGGER.error("put mapping failed:" + e.getMessage(), e);
            return new APIResult<>(APICode.SYS_EXCEPTION, e.getMessage());
        }
        return new APIResult<>(APICode.SUCCESS, response);
    }

    @RequestMapping(value = "/{index}/{mapping}",method = RequestMethod.POST)
    public @ResponseBody APIResult<Object> postMapping(@PathVariable String index,@PathVariable String mapping,@RequestBody String query) {
        APICode apiCode = checkJson(query);
        if(!apiCode.equals(APICode.SUCCESS)){
            return new APIResult<Object>(apiCode);
        }
        SearchResponse response = null;
        try {
            response = elastic.search(index, mapping, query);
        } catch (Exception e) {
            LOGGER.error("search failed:" + e.getMessage(), e);
            return new APIResult<>(APICode.SYS_EXCEPTION, e.getMessage());
        }
        String responseJson = response.toString();
        JsonNode json = null;
        try {
            json = Config.JSON_MAPPER.readValue(responseJson, JsonNode.class);
        } catch (IOException e) {
            LOGGER.error("parse json failed:" + e.getMessage(), e);
            return new APIResult<>(APICode.SYS_EXCEPTION, e.getMessage());
        }
        return new APIResult<>(APICode.SUCCESS, json);
    }

    @RequestMapping(value = "/{index}/{mapping}/{id}",method = RequestMethod.POST)
    public @ResponseBody APIResult<Object> postId(@PathVariable String index,@PathVariable String mapping,@PathVariable String id,@RequestBody String source) {
        APICode apiCode = checkJson(source);
        if(!apiCode.equals(APICode.SUCCESS)){
            return new APIResult<Object>(apiCode);
        }
        IndexResponse response = null;
        try {
            response = elastic.index(index, mapping, id, source);
        } catch (Exception e) {
            LOGGER.error("index data for id failed:" + e.getMessage(), e);
            return new APIResult<>(APICode.SYS_EXCEPTION, e.getMessage());
        }
        return new APIResult<>(APICode.SUCCESS, response);
    }

    @RequestMapping(value = "/{index}",method = RequestMethod.DELETE)
    public @ResponseBody APIResult<Object> deleteIndex(@PathVariable String index) {
        DeleteIndexResponse response = null;
        try {
            response = elastic.deleteIndex(index);
        } catch (Exception e) {
            LOGGER.error("delete index failed:" + e.getMessage(), e);
            return new APIResult<>(APICode.SYS_EXCEPTION, e.getMessage());
        }
        return new APIResult<>(APICode.SUCCESS, response);
    }

    @RequestMapping(value = "/{index}/{mapping}/{id}",method = RequestMethod.DELETE)
    public @ResponseBody APIResult<Object> deleteId(@PathVariable String index,@PathVariable String mapping,@PathVariable String id) {
        DeleteResponse response = null;
        try {
            response = elastic.deleteById(index, mapping, id);
        } catch (Exception e) {
            LOGGER.error("delete by id failed:" + e.getMessage(), e);
            return new APIResult<>(APICode.SYS_EXCEPTION, e.getMessage());
        }
        return new APIResult<>(APICode.SUCCESS, response);
    }

    @RequestMapping(value = "/{index}/{mapping}", method = RequestMethod.DELETE)
    @ResponseBody
    public APIResult<Object> deleteMapping(@PathVariable String index, @PathVariable String mapping,@RequestBody String source) {
        BulkByScrollResponse response = null;
        try {
            response = elastic.deleteMapping(index, mapping,source);
        } catch (Exception e) {
            LOGGER.error("delete mapping failed:" + e.getMessage(), e);
            return new APIResult<>(APICode.SYS_EXCEPTION, e.getMessage());
        }
        return new APIResult<>(APICode.SUCCESS, response);
    }

}
